package org.ghost.springboot.demo.component.monitor;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.ghost.springboot.demo.common.component.RequestContext;
import org.ghost.springboot.demo.util.ExceptionUtil;
import org.ghost.springboot.demo.util.JacksonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.function.Supplier;

@Aspect
@Component
public class ApiControllerMonitor {
    private static final Logger logger = LoggerFactory.getLogger(ApiControllerMonitor.class);

    public ApiControllerMonitor() {
    }

    /**
     * 记录controller方法前所有的日志
     *
     * @param joinPoint 不能为空
     */
    @Before("execution(* org.ghost.springboot.demo..controller..*.*(..))")
    public void pointBeforeMethodInvoke(JoinPoint joinPoint) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        StringBuilder sb = new StringBuilder("---------- Starting : ");
        sb.append(joinPoint.getSignature().getDeclaringTypeName());
        sb.append(".");
        sb.append(joinPoint.getSignature().getName());
        sb.append(logAllParamsInfo(joinPoint));
        sb.append("TAG_UUID:");
        sb.append(RequestContext.getContext().getId());
        sb.append(", Token:");
        sb.append(request.getParameter("token"));
        sb.append(" --------");
        info(sb::toString);
    }

    @AfterReturning(value = "execution(* org.ghost.springboot.demo..controller..*.*(..))", returning = "result", argNames = "result")
    public void pointAfterMethodInvoke(JoinPoint joinPoint, Object result) {
        String text = (result != null && result instanceof Serializable) ? JacksonUtil.useDefaultMapper().toJson(result) : result + "";
        info(() -> "******** ending : " + joinPoint.getSignature().getDeclaringTypeName()
                + "." + joinPoint.getSignature().getName() + " ******"
                + ";IP->" + RequestContext.getContext().getClientIp()
                + ";耗时(sec)->" + ((System.currentTimeMillis() - RequestContext.getContext().getBeginTime()) / 1000.0)
                + ";返回结果->" + text);

        RequestContext.remove();
    }

    @AfterThrowing(value = "execution(* org.ghost.springboot.demo..controller..*.*(..))", throwing = "exception", argNames = "exception")
    public void pointAfterThrowingMethodInvoke(JoinPoint joinPoint, Throwable exception) {
        info(() -> "******** throwing : " + joinPoint.getSignature().getDeclaringTypeName()
                + "." + joinPoint.getSignature().getName() + " ******"
                + ";IP->" + RequestContext.getContext().getClientIp()
                + ";耗时(sec)->" + ((System.currentTimeMillis() - RequestContext.getContext().getBeginTime()) / 1000.0)
                + ";异常信息->" + ExceptionUtil.getExceptionStack(exception));

        //todo 暂时不移除,交给@ControllerAdvice处理之后移除
        //RequestContext.remove();
    }

    /**
     * 记录切点当前方法所有的参数
     *
     * @param joinPoint 不能为空
     */
    private String logAllParamsInfo(JoinPoint joinPoint) {
        StringBuilder sb = new StringBuilder();
        try {
            Object[] args = joinPoint.getArgs();
            int index = 0;
            for (Object arg : args) {
                if (arg != null) {
                    if (arg instanceof Serializable) {
                        sb.append(" param").append(index).append(": ").append(JacksonUtil.useDefaultMapper().toJson(arg));
                    } else {
                        sb.append(" param").append(index).append(": ").append(arg);
                    }
                } else {
                    sb.append(" param").append(index).append(": null");
                }
                index++;
            }
        } catch (Exception ex) {
            info(() -> "*****ApiControllerMonitor-logAllParamsInfo****参数解析错误:" + ex.getMessage());
        }

        return sb.toString();
    }

    /**
     * debug级别日志输出
     *
     * @param supplier 不能为空
     */
    private void info(Supplier<String> supplier) {
        if (logger.isInfoEnabled()) {
            logger.info("*****ApiControllerMonitor-info: " + supplier.get());
        }
    }

//    private CustomerKeyInfoRspDTO handleRequestPara(HttpServletRequest request) {
//        if (request != null) {
//            //查找url参数
//            long customerId = NumberUtil.toLong(request.getParameter(SystemConstant.KEY_CUSTOMER_ID), 0L);
//            long clientSn = ContractUtil.getClientSn(request.getParameter(SystemConstant.KEY_CLIENT_SN));
//            long leadSn = ContractUtil.getClientSn(request.getParameter(SystemConstant.KEY_LEAD_SN));
//            String mobile = request.getParameter(SystemConstant.KEY_CUSTOMER_MOBILE);
//
//            //查找pathVariale参数,clientSn/123456;customerId/123456,mobile/123456
//            if (customerId == 0L && clientSn == 0L && leadSn == 0L && StringUtils.isBlank(mobile)) {
//                ///api/selfCourse/product/clientSn/2615555
//                String reqUri = request.getRequestURI();
//                if (reqUri.contains(SystemConstant.KEY_CUSTOMER_ID + "/")) {
//                    String paraValue = this.getPathVariablePara(reqUri, SystemConstant.KEY_CUSTOMER_ID);
//                    if (StringUtils.isNotBlank(paraValue)) {
//                        customerId = NumberUtil.toLong(paraValue, 0L);
//                    }
//                } else if (reqUri.contains(SystemConstant.KEY_CLIENT_SN + "/")) {
//                    String paraValue = this.getPathVariablePara(reqUri, SystemConstant.KEY_CLIENT_SN);
//                    if (StringUtils.isNotBlank(paraValue)) {
//                        clientSn = ContractUtil.getClientSn(paraValue);
//                    }
//                } else if (reqUri.contains(SystemConstant.KEY_LEAD_SN + "/")) {
//                    String paraValue = this.getPathVariablePara(reqUri, SystemConstant.KEY_LEAD_SN);
//                    if (StringUtils.isNotBlank(paraValue)) {
//                        leadSn = NumberUtil.toLong(paraValue, 0L);
//                    }
//                } else if (reqUri.contains(SystemConstant.KEY_CUSTOMER_MOBILE + "/")) {
//                    //url链接存在mobile/lesson这样的地址
//                    String tempVal = this.getPathVariablePara(reqUri, SystemConstant.KEY_CUSTOMER_MOBILE);
//                    if (NumberUtils.isDigits(mobile)) {
//                        mobile = tempVal;
//                    }
//                }
//            }
//
//            //从body里面取数据
//            if (customerId == 0L && clientSn == 0L && leadSn == 0L && StringUtils.isBlank(mobile)) {
//                String methodName = request.getMethod();
//                if (Objects.equals(HttpMethod.POST.name(), methodName)
//                        || Objects.equals(HttpMethod.PUT.name(), methodName)
//                        || Objects.equals(HttpMethod.PATCH.name(), methodName)
//                        || Objects.equals(HttpMethod.DELETE.name(), methodName)) {
//                    ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
//                    MediaType contentType = inputMessage.getHeaders().getContentType();
//                    if ((Objects.equals(MediaType.APPLICATION_JSON, contentType) || Objects.equals(MediaType.APPLICATION_JSON_UTF8, contentType))) {
//                        try {
//                            InputStream in = inputMessage.getBody();
//                            String text = IOUtils.toString(in, "UTF-8");
//                            Map<String, Object> bodyMap = null;
//                            if (StringUtils.isNotBlank(text) && text.startsWith("{")) {
//                                //{}类型
//                                Type mapType = ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, Object.class}, null);
//                                TypeReference<Map<String, Object>> typeReference = new TypeReference<Map<String, Object>>() {
//                                    @Override
//                                    public Type getType() {
//                                        return mapType;
//                                    }
//                                };
//                                bodyMap = JacksonUtil.useDefaultMapper().fromJson(text, typeReference);
//                            } else if (StringUtils.isNotBlank(text) && text.startsWith("[")) {
//                                if (text.startsWith("[{")) {
//                                    //[{},{}]类型
//                                    Type mapType = ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, Object.class}, null);
//                                    Type listMapType = ParameterizedTypeImpl.make(List.class, new Type[]{mapType}, null);
//                                    TypeReference<List<Map<String, Object>>> typeReference = new TypeReference<List<Map<String, Object>>>() {
//                                        @Override
//                                        public Type getType() {
//                                            return listMapType;
//                                        }
//                                    };
//                                    List<Map<String, Object>> bodyListMap = JacksonUtil.useDefaultMapper().fromJson(text, typeReference);
//                                    if (CollectionUtils.isNotEmpty(bodyListMap) && bodyListMap.size() == 1) {
//                                        bodyMap = bodyListMap.get(0);
//                                    }
//                                }
////                                else {
////                                    //[A,B,C]类型
////                                    Type listType = ParameterizedTypeImpl.make(List.class, new Type[]{String.class}, null);
////                                    TypeReference<List<String>> typeReference = new TypeReference<List<String>>() {
////                                        @Override
////                                        public Type getType() {
////                                            return listType;
////                                        }
////                                    };
////                                    List<String> stringList = JacksonUtil.useDefaultMapper().fromJson(text, typeReference);
////                                    if (CollectionUtils.isNotEmpty(stringList) && stringList.size() == 1) {
////                                        clientSn = ContractUtil.getClientSn(stringList.get(0));
////                                    }
////                                }
//                            }
//
//                            if (MapUtils.isNotEmpty(bodyMap)) {
//                                customerId = MapUtils.getLong(bodyMap, SystemConstant.KEY_CUSTOMER_ID, 0L);
//                                //有些参数名为clientSn,但是传入的却是一个List
//                                String clientSnStr = MapUtils.getString(bodyMap, SystemConstant.KEY_CLIENT_SN);
//                                if (StringUtils.isNotBlank(clientSnStr) && !clientSnStr.startsWith("[") && !clientSnStr.startsWith("{")) {
//                                    clientSn = ContractUtil.getClientSn(clientSnStr);
//                                }
//                                leadSn = MapUtils.getLong(bodyMap, SystemConstant.KEY_LEAD_SN, 0L);
//                                mobile = MapUtils.getString(bodyMap, SystemConstant.KEY_CUSTOMER_MOBILE);
//                            }
//                        } catch (Exception e) {
//                            logger.error("*****解析request的body数据出错:" + e.getMessage(), e);
//                        }
//                    }
//                }
//            }
//
//            if (customerId > 0L || clientSn > 0L) {
//                CustomerKeyInfoReqDTO customerKeyInfoReqDTO = new CustomerKeyInfoReqDTO();
//                if (customerId > 0L) {
//                    customerKeyInfoReqDTO.setCustomerId(customerId);
//                } else if (clientSn > 0L) {
//                    customerKeyInfoReqDTO.setClientSn(clientSn);
//                }
//
//                try {
//                    return this.customerInfoService.getCustomerKeyInfo(customerKeyInfoReqDTO);
//                } catch (Exception e) {
//                    logger.error("*****ApiControllerMonitor.handleRequestPara查询用户信息出现异常:" + e.getMessage(), e);
//                }
//            }
//
////            if (customerId > 0L || clientSn > 0L || leadSn > 0L || StringUtils.isNotBlank(mobile)) {
////                CustomerKeyInfoReqDTO customerKeyInfoReqDTO = new CustomerKeyInfoReqDTO();
////                if (customerId > 0L) {
////                    customerKeyInfoReqDTO.setCustomerId(customerId);
////                } else if (clientSn > 0L) {
////                    customerKeyInfoReqDTO.setClientSn(clientSn);
////                } else if (leadSn > 0L) {
////                    customerKeyInfoReqDTO.setLeadSn(leadSn);
////                } else if (StringUtils.isNotBlank(mobile)) {
////                    customerKeyInfoReqDTO.setMobile(mobile);
////                }
////                try {
////                    return this.customerInfoService.getCustomerKeyInfo(customerKeyInfoReqDTO);
////                } catch (Exception e) {
////                    logger.error("*****ApiControllerMonitor.handleRequestPara查询用户信息出现异常:" + e.getMessage(), e);
////                }
////            }
//        }
//
//        return null;
//    }
//
//    /**
//     * 从地址/api/selfCourse/product/clientSn/2615555中取出2615555
//     * 从地址/api/selfCourse/product/clientSn/2615555/abc中取出2615555
//     *
//     * @param reqUri
//     * @param paraName
//     * @return
//     */
//    private String getPathVariablePara(final String reqUri, final String paraName) {
//        if (StringUtils.isNotBlank(reqUri) && StringUtils.isNotBlank(paraName)) {
//            int begin = reqUri.indexOf(paraName + "/", 0);
//            int fromIndex = begin + paraName.length() + 1;
//            int end = reqUri.indexOf("/", fromIndex);
//            if (begin > -1 && end > begin) {
//                return reqUri.substring(fromIndex, end);
//            } else if (begin > -1 && end == -1) {
//                return reqUri.substring(fromIndex);
//            }
//        }
//
//        return "";
//    }
}
